package top.kaoshanji.ch01.collecting;

import com.google.common.io.Resources;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import static java.util.stream.Collectors.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Stream;

/**
 * 代码清单 ch01-06：下游收集器示例(1.11/12节)
 * author kaoshanji
 * ^_^
 * create time 2024/12/5 18:53
 */
public class DownstreamCollectors {

    private static final Logger logger = LogManager.getLogger(DownstreamCollectors.class);

    static final String FILE_NAME = "ch01/cities.txt";

    public static void main(String[] args) throws IOException {
        logger.info("...代码清单 ch01-06：下游收集器示例(1.11/12节)...");

        // 【例1】 键：字符串、值：Set...在groupingBy里面操作啊
        // 以国家分组，每个国家语言集合
        Stream<Locale> locales = Stream.of(Locale.getAvailableLocales());
        Map<String, Set<Locale>> countryToLocaleSet = locales.collect(groupingBy(Locale::getCountry, toSet()));
        System.out.println("countryToLocaleSet: " + countryToLocaleSet);

        // 【例2】 键：字符串、值：数字...分组的数量
        // 以国家分组，每个国家语言数量
        locales = Stream.of(Locale.getAvailableLocales());
        Map<String, Long> countryToLocaleCounts = locales.collect(groupingBy(Locale::getCountry, counting()));
        System.out.println("countryToLocaleCounts: " + countryToLocaleCounts);

        // 【例3】 键：字符串、值：数字...分组的总和
        // 以州为单位，统计每州的人口数量
        Stream<City> cities = readCities(FILE_NAME);
        Map<String, Integer> stateToCityPopulation = cities.collect(groupingBy(City::getState, summingInt(City::getPopulation)));
        System.out.println("stateToCityPopulation: " + stateToCityPopulation);

        // 【例4】 键：字符串、值：Optional
        // 以州为单位，选择该州内城市名称最长的
        // 看看后面的右括号，数量足有5个...
        cities = readCities(FILE_NAME);
        Map<String, Optional<String>> stateToLongestCityName = cities.collect(groupingBy(City::getState, mapping(City::getName, maxBy(Comparator.comparing(String::length)))));
        System.out.println("stateToLongestCityName: " + stateToLongestCityName);

        // 【例5】 键：字符串、值：Set集合
        // 以国家为单位，将该国家的语言转换为Set集合
        locales = Stream.of(Locale.getAvailableLocales());
        Map<String, Set<String>> countryToLanguages = locales.collect(groupingBy(
                Locale::getDisplayCountry, mapping(Locale::getDisplayLanguage, toSet())));
        System.out.println("countryToLanguages: " + countryToLanguages);

        // 【例6】 键：字符串、值：IntSummaryStatistics
        // 以州为单位，每州一个IntSummaryStatistics对象，然后就可以总和、数量、平均值、最小值和最大值
        cities = readCities(FILE_NAME);
        Map<String, IntSummaryStatistics> stateToCityPopulationSummary = cities.collect(groupingBy(City::getState, summarizingInt(City::getPopulation)));
        System.out.println(stateToCityPopulationSummary.get("NY"));

        // 【例7】 这个不懂了..这是 1.12节的示例
        // cities = readCities(FILE_NAME);
        // Map<String, String> stateToCityNames = cities.collect(groupingBy(City::getState, reducing("", City::getName,
        //        (s, t) -> s.length() == 0 ? t : s + ", " + t)));

        // 【例8】 键：字符串、值：字符串
        // 以州为单位，将城市的名字使用分隔符连接起来
        cities = readCities(FILE_NAME);
        Map<String, String> stateToCityNames = cities.collect(groupingBy(City::getState, mapping(City::getName, joining(", "))));
        System.out.println("stateToCityNames: " + stateToCityNames);

    }


    public static Stream<City> readCities(String fileName) throws IOException {
        List<String> list = Resources.readLines(Resources.getResource(fileName), StandardCharsets.UTF_8);
        // 两层 map...
        return list.stream().map(l -> l.split(", ")).map(y -> new City(y[0], y[1], Integer.parseInt(y[2])));
    }

}
